package com.fjsh.aop;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;

/**
 * Web层日志切面
 * 此处简单示例，因为是微服务架构，所以需搭建链路追踪服务，并收集对应的trackId
 * TODO:整合链路追踪，使用skywalking框架，优点：国人开发，友好的UI界面，代码无侵入
 */
@Slf4j
@Aspect    //这里使用@Aspect注解方式设置AOP
@Order(5)  //值越小,越先加载
@Component
public class WebLogAop {

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 这里@Pointcut设置切点可以设置为Controller层的地址
     */
    @Pointcut("execution(* com.fjsh.web..*(..))")
    public void webLog(){}

	//@Before指在切点方法之前执行,也就是在Controller层方法执行之前执行,这里可以通过JoinPoint获取一些有关方法的信息,在这里也可以修改参数的值

    /**
     * @Before()括号里设置的是切点方法的名称
     */
	@Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        startTime.set(System.currentTimeMillis());

        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 记录下请求内容
        log.info("请求开始时间(START_TIME) : " + LocalDateTime.now());
        log.info("请求路径(URL) : " + request.getRequestURL().toString());
        log.info("请求方式(HTTP_METHOD) : " + request.getMethod());
        log.info("IP地址(IP) : " + request.getRemoteAddr());
        log.info("请求方法(CLASS_METHOD) : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("请求参数(ARGS) : " + Arrays.toString(joinPoint.getArgs()));

    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容
        log.info("响应内容(RESPONSE) : " + JSON.toJSONString(ret));
        log.info("请求开始时间(START_TIME) : " + LocalDateTime.now());
        log.info("消耗时长(SPEND_TIME) : " + (System.currentTimeMillis() - startTime.get()));
    }

}